#include "../include/Menu.h"
#include <iostream>
#include <iomanip>
#include <algorithm>


// 构造函数实现
Menu::Menu() : fileManager(std::make_unique<FileManager>()) {
    // 创建必要的目录
    FileManager::createDirectories();
    // 加载数据
    loadData();
 // 如果没有课程，初始化默认课程
    if (courses.empty()) {
        initializeDefaultCourses();
        saveData();
    }
}

// 初始化默认课程
void Menu::initializeDefaultCourses() {
    // 计算机科学与技术专业核心课程
    courses.emplace_back("CS101", "计算机导论", 3, "张教授");
    courses.emplace_back("CS102", "程序设计基础(C语言)", 4, "李教授");
    courses.emplace_back("CS103", "数据结构", 4, "王教授");
    courses.emplace_back("CS201", "面向对象程序设计(C++)", 4, "赵教授");
    courses.emplace_back("CS202", "算法分析与设计", 3, "刘教授");
    courses.emplace_back("CS203", "操作系统", 4, "陈教授");
    courses.emplace_back("CS204", "计算机网络", 3, "杨教授");
    courses.emplace_back("CS205", "数据库系统", 4, "周教授");
    courses.emplace_back("CS301", "软件工程", 3, "吴教授");
    courses.emplace_back("CS302", "人工智能", 3, "郑教授");
    courses.emplace_back("CS303", "编译原理", 4, "孙教授");
    courses.emplace_back("CS304", "计算机组成原理", 4, "马教授");
    
    // 软件工程专业特色课程
    courses.emplace_back("SE101", "软件需求分析", 3, "高教授");
    courses.emplace_back("SE102", "软件测试技术", 3, "林教授");
    courses.emplace_back("SE103", "软件项目管理", 3, "黄教授");
    
    // 人工智能专业特色课程
    courses.emplace_back("AI101", "机器学习", 4, "石教授");
    courses.emplace_back("AI102", "深度学习", 4, "钱教授");
    courses.emplace_back("AI103", "自然语言处理", 3, "孟教授");
    
    // 网络安全专业特色课程
    courses.emplace_back("NS101", "网络安全基础", 3, "谢教授");
    courses.emplace_back("NS102", "密码学", 4, "邓教授");
    courses.emplace_back("NS103", "安全编程", 3, "冯教授");
    
    std::cout << "已初始化默认计算机专业课程！" << std::endl;
}

// 运行菜单方法实现
void Menu::run() {
    // 添加一个默认学生，如果没有学生的话
    if (students.empty()) {
        students.emplace_back("2023001", "张三", "男", "计算机科学与技术");
        saveData();
        std::cout << "已添加默认学生账号：学号 2023001，姓名 张三" << std::endl;
    }
    
    int choice = 0;
    do {
        displayMainMenu();
        std::cout << "请输入您的选择: ";
        std::cin >> choice;
        
        switch (choice) {
            case 1: // 选课管理
                int selectionChoice;
                do {
                    displaySelectionMenu();
                    std::cout << "请输入您的选择: ";
                    std::cin >> selectionChoice;
                    
                    switch (selectionChoice) {
                        case 1: displayAvailableCourses(); break;
                        case 2: addSelection(); break;
                        case 3: displaySelections(); break;
                        case 4: searchSelection(); break;
                        case 5: modifySelection(); break;
                        case 6: removeSelection(); break;
                        case 0: break;
                        default: std::cout << "无效选择，请重试。" << std::endl;
                    }
                } while (selectionChoice != 0);
                break;
                
            case 0: // 退出系统
                saveData();
                std::cout << "感谢使用选课管理系统，再见！" << std::endl;
                break;
                
            default:
                std::cout << "无效选择，请重试。" << std::endl;
        }
    } while (choice != 0);
}

// 显示主菜单方法实现
void Menu::displayMainMenu() const {
    std::cout << "\n========== 学生选课系统 ==========" << std::endl;
    std::cout << "1. 选课管理" << std::endl;
    std::cout << "0. 退出系统" << std::endl;
    std::cout << "================================" << std::endl;
}

// 显示选课菜单方法实现
void Menu::displaySelectionMenu() const {
    std::cout << "\n========== 选课管理 ==========" << std::endl;
    std::cout << "1. 查看可选课程" << std::endl;
    std::cout << "2. 添加选课" << std::endl;
    std::cout << "3. 查看已选课程" << std::endl;
    std::cout << "4. 查找选课信息" << std::endl;
    std::cout << "5. 修改选课信息" << std::endl;
    std::cout << "6. 退选课程" << std::endl;
    std::cout << "0. 返回主菜单" << std::endl;
    std::cout << "===========================" << std::endl;
}

// 显示可选课程方法实现
void Menu::displayAvailableCourses() const {
    if (courses.empty()) {
        std::cout << "没有可选课程！" << std::endl;
        return;
    }
    
    std::cout << "\n========== 可选课程列表 ==========" << std::endl;
    std::cout << "课程编号\t课程名称\t学分\t授课教师" << std::endl;
    std::cout << "----------------------------------------" << std::endl;
    
    // 按专业分类显示课程
    std::cout << "\n【计算机科学与技术专业核心课程】" << std::endl;
    for (const auto& course : courses) {
        if (course.getId().substr(0, 2) == "CS") {
            std::cout << course << std::endl;
        }
    }
    
    std::cout << "\n【软件工程专业特色课程】" << std::endl;
    for (const auto& course : courses) {
        if (course.getId().substr(0, 2) == "SE") {
            std::cout << course << std::endl;
        }
    }
    
    std::cout << "\n【人工智能专业特色课程】" << std::endl;
    for (const auto& course : courses) {
        if (course.getId().substr(0, 2) == "AI") {
            std::cout << course << std::endl;
        }
    }
    
    std::cout << "\n【网络安全专业特色课程】" << std::endl;
    for (const auto& course : courses) {
        if (course.getId().substr(0, 2) == "NS") {
            std::cout << course << std::endl;
        }
    }
}

// 添加选课信息方法实现
void Menu::addSelection() {
    std::string studentId, courseId, semester;
    
    // 显示当前学生列表
    std::cout << "当前系统中的学生：" << std::endl;
    for (const auto& student : students) {
        std::cout << "学号: " << student.getId() << ", 姓名: " << student.getName() << std::endl;
    }
    
    std::cout << "请输入您的学号: ";
    std::cin >> studentId;
    
    // 检查学生是否存在
    int studentIndex = findStudentById(studentId);
    if (studentIndex == -1) {
        std::cout << "该学号不存在！请确认后重试。" << std::endl;
        return;
    }
    
    // 显示可选课程
    displayAvailableCourses();
    
    std::cout << "请输入要选择的课程编号: ";
    std::cin >> courseId;
    
    // 检查课程是否存在
    int courseIndex = findCourseById(courseId);
    if (courseIndex == -1) {
        std::cout << "该课程不存在！请确认后重试。" << std::endl;
        return;
    }
    
    // 检查是否已选过该课程
    if (findSelection(studentId, courseId) != -1) {
        std::cout << "您已经选过这门课程了！" << std::endl;
        return;
    }
    
    // 默认使用当前学期
    semester = "2023-2024学年第一学期";
    
    // 添加选课记录，初始成绩设为-1（未录入）
    selections.emplace_back(studentId, courseId, semester, -1);
    std::cout << "选课成功！您已选择 " << courses[courseIndex].getName() << " 课程。" << std::endl;
    
    // 自动保存数据
    saveData();
}

// 显示所有选课信息方法实现
void Menu::displaySelections() const {
    std::string studentId;
    std::cout << "请输入您的学号: ";
    std::cin >> studentId;
    
    // 检查学生是否存在
    int studentIndex = findStudentById(studentId);
    if (studentIndex == -1) {
        std::cout << "该学号不存在！请确认后重试。" << std::endl;
        return;
    }
    
    // 查找该学生的所有选课记录
    bool found = false;
    double totalCredits = 0.0;
    
    std::cout << "\n========== " << students[studentIndex].getName() << " 的选课记录 ==========" << std::endl;
    std::cout << "课程编号\t课程名称\t学分\t授课教师\t学期\t成绩" << std::endl;
    std::cout << "------------------------------------------------------" << std::endl;
    
    for (const auto& selection : selections) {
        if (selection.getStudentId() == studentId) {
            int courseIndex = findCourseById(selection.getCourseId());
            
            if (courseIndex != -1) {
                std::cout << selection.getCourseId() << "\t"
                          << courses[courseIndex].getName() << "\t"
                          << courses[courseIndex].getCredit() << "\t"
                          << courses[courseIndex].getTeacher() << "\t"
                          << selection.getSemester() << "\t";
                
                if (selection.getScore() < 0) {
                    std::cout << "未录入" << std::endl;
                } else {
                    std::cout << selection.getScore() << std::endl;
                }
                
                totalCredits += courses[courseIndex].getCredit();
                found = true;
            }
        }
    }
    
    if (found) {
        std::cout << "\n总学分: " << totalCredits << std::endl;
    } else {
        std::cout << "您还没有选课记录！" << std::endl;
    }
}

// 查找选课信息方法实现
void Menu::searchSelection() const {
    std::string studentId, courseId;
    std::cout << "请输入您的学号: ";
    std::cin >> studentId;
    
    // 检查学生是否存在
    int studentIndex = findStudentById(studentId);
    if (studentIndex == -1) {
        std::cout << "该学号不存在！请确认后重试。" << std::endl;
        return;
    }
    
    std::cout << "请输入要查询的课程编号(直接回车查询所有): ";
    std::cin.ignore();
    std::getline(std::cin, courseId);
    
    if (courseId.empty()) {
        // 显示所有选课记录
        displaySelections();
        return;
    }
    
    // 查找特定课程的选课记录
    int index = findSelection(studentId, courseId);
    if (index == -1) {
        std::cout << "未找到该选课记录！" << std::endl;
        return;
    }
    
    int courseIndex = findCourseById(courseId);
    if (courseIndex != -1) {
        std::cout << "\n课程编号\t课程名称\t学分\t授课教师\t学期\t成绩" << std::endl;
        std::cout << "------------------------------------------------------" << std::endl;
        std::cout << selections[index].getCourseId() << "\t"
                  << courses[courseIndex].getName() << "\t"
                  << courses[courseIndex].getCredit() << "\t"
                  << courses[courseIndex].getTeacher() << "\t"
                  << selections[index].getSemester() << "\t";
        
        if (selections[index].getScore() < 0) {
            std::cout << "未录入" << std::endl;
        } else {
            std::cout << selections[index].getScore() << std::endl;
        }
    }
}

// 修改选课信息方法实现
void Menu::modifySelection() {
    std::string studentId, courseId;
    std::cout << "请输入您的学号: ";
    std::cin >> studentId;
    
    // 检查学生是否存在
    int studentIndex = findStudentById(studentId);
    if (studentIndex == -1) {
        std::cout << "该学号不存在！请确认后重试。" << std::endl;
        return;
    }
    
    // 显示该学生的所有选课记录
    bool found = false;
    std::cout << "\n您的选课记录：" << std::endl;
    std::cout << "课程编号\t课程名称" << std::endl;
    std::cout << "-------------------" << std::endl;
    
    for (const auto& selection : selections) {
        if (selection.getStudentId() == studentId) {
            int courseIndex = findCourseById(selection.getCourseId());
            if (courseIndex != -1) {
                std::cout << selection.getCourseId() << "\t"
                          << courses[courseIndex].getName() << std::endl;
                found = true;
            }
        }
    }
    
    if (!found) {
        std::cout << "您还没有选课记录！" << std::endl;
        return;
    }
    
    std::cout << "请输入要修改的课程编号: ";
    std::cin >> courseId;
    
    int index = findSelection(studentId, courseId);
    if (index == -1) {
        std::cout << "未找到该选课记录！" << std::endl;
        return;
    }
    
    // 在学生选课系统中，学生只能修改学期信息
    std::string semester;
    std::cout << "请输入新的学期(原学期: " << selections[index].getSemester() << "): ";
    std::cin.ignore();
    std::getline(std::cin, semester);
    
    if (!semester.empty()) {
        selections[index].setSemester(semester);
        std::cout << "选课信息修改成功！" << std::endl;
        saveData(); // 自动保存数据
    } else {
        std::cout << "未进行任何修改。" << std::endl;
    }
}

// 删除选课信息方法实现
void Menu::removeSelection() {
    std::string studentId, courseId;
    std::cout << "请输入您的学号: ";
    std::cin >> studentId;
    
    // 检查学生是否存在
    int studentIndex = findStudentById(studentId);
    if (studentIndex == -1) {
        std::cout << "该学号不存在！请确认后重试。" << std::endl;
        return;
    }
    
    // 显示该学生的所有选课记录
    bool found = false;
    std::cout << "\n您的选课记录：" << std::endl;
    std::cout << "课程编号\t课程名称" << std::endl;
    std::cout << "-------------------" << std::endl;
    
    for (const auto& selection : selections) {
        if (selection.getStudentId() == studentId) {
            int courseIndex = findCourseById(selection.getCourseId());
            if (courseIndex != -1) {
                std::cout << selection.getCourseId() << "\t"
                          << courses[courseIndex].getName() << std::endl;
                found = true;
            }
        }
    }
    
    if (!found) {
        std::cout << "您还没有选课记录！" << std::endl;
        return;
    }
    
    std::cout << "请输入要退选的课程编号: ";
    std::cin >> courseId;
    
    int index = findSelection(studentId, courseId);
    if (index == -1) {
        std::cout << "未找到该选课记录！" << std::endl;
        return;
    }
    
    int courseIndex = findCourseById(courseId);
    std::string courseName = (courseIndex != -1) ? courses[courseIndex].getName() : courseId;
    
    char confirm;
    std::cout << "确定要退选 " << courseName << " 课程吗？(y/n): ";
    std::cin >> confirm;
    
    if (confirm == 'y' || confirm == 'Y') {
        selections.erase(selections.begin() + index);
        std::cout << "课程退选成功！" << std::endl;
        saveData(); // 自动保存数据
    } else {
        std::cout << "已取消退选操作。" << std::endl;
    }
}

// 保存数据方法实现
void Menu::saveData() const {
    bool success = true;
    success &= fileManager->saveStudents(students);
    success &= fileManager->saveCourses(courses);
    success &= fileManager->saveSelections(selections);
    
    if (!success) {
        std::cout << "数据保存过程中出现错误！" << std::endl;
    }
}

// 加载数据方法实现
void Menu::loadData() {
    bool success = true;
    success &= fileManager->loadStudents(students);
    success &= fileManager->loadCourses(courses);
    success &= fileManager->loadSelections(selections);
    
    if (!success) {
        std::cout << "数据加载过程中出现错误！" << std::endl;
    }
}

// 查找学生方法实现
int Menu::findStudentById(const std::string& id) const {
    for (size_t i = 0; i < students.size(); ++i) {
        if (students[i].getId() == id) {
            return static_cast<int>(i);
        }
    }
    return -1;
}

// 查找课程方法实现
int Menu::findCourseById(const std::string& id) const {
    for (size_t i = 0; i < courses.size(); ++i) {
        if (courses[i].getId() == id) {
            return static_cast<int>(i);
        }
    }
    return -1;
}

// 查找选课信息方法实现
int Menu::findSelection(const std::string& studentId, const std::string& courseId) const {
    for (size_t i = 0; i < selections.size(); ++i) {
        if (selections[i].getStudentId() == studentId && selections[i].getCourseId() == courseId) {
            return static_cast<int>(i);
        }
    }
    return -1;
}